﻿using CommunityToolkit.Mvvm.Input;
using DeepSeek.Core;
using DeepSeek.Core.Models;
using OpenGptChat.Services;
using OpenGptChat.Utilities;
using OpenGptChat.ViewModels;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.WebSockets;
using System.Text;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Controls;
using System.Windows.Input;

namespace OpenGptChat.Views.Pages
{
    /// <summary>
    /// Interaction logic for ChatPage.xaml
    /// </summary>
    public partial class ChatPage : Page
    {
        XunFeiApi xunFeiApi = new XunFeiApi();
        public ChatPage(
            ChatPageModel viewModel,
            NoteService noteService,
            ChatService chatService,
            ChatStorageService chatStorageService,
            ConfigurationService configurationService,
            SmoothScrollingService smoothScrollingService)
        {
            ViewModel = viewModel;
            NoteService = noteService;
            ChatService = chatService;
            ChatStorageService = chatStorageService;
            ConfigurationService = configurationService;
            DataContext = this;

            InitializeComponent();
            xunFeiApi.OnSomethingHappened += HandleOnSomethingHappened;

            messageScrollViewer.PreviewMouseWheel += CloseAutoScrollWhileMouseWheel;
            messageScrollViewer.ScrollChanged += EnableAutoScrollWhileAtEnd;
            smoothScrollingService.Register(messageScrollViewer);
        }

        private void HandleOnSomethingHappened(string message)
        {
            ViewModel.Messages[_index].Content = ViewModel.Messages[_index].Content + message;
        }

        public ChatPageModel ViewModel { get; }
        public ChatService ChatService { get; }
        public ChatStorageService ChatStorageService { get; }
        public NoteService NoteService { get; }
        public ConfigurationService ConfigurationService { get; }

        public Guid SessionId { get; private set; }


        public void InitSession(Guid sessionId)
        {
            SessionId = sessionId;

            ViewModel.Messages.Clear();
            foreach (var msg in ChatStorageService.GetAllMessages(SessionId))
                ViewModel.Messages.Add(
                    new ChatMessageModel(msg));
        }

        public async Task StreamChatAsync(DeepSeekClient client, string input, ChatMessageModel chatMessage)
        {

        }
        private int _index;
        [RelayCommand]
        public async Task ChatAsync()
        {
            if (string.IsNullOrWhiteSpace(ViewModel.InputBoxText))
            {
                _ = NoteService.ShowAndWaitAsync("Empty message", 1500);
                return;
            }

            //if (string.IsNullOrWhiteSpace(ConfigurationService.Configuration.ApiKey))
            //{
            //    await NoteService.ShowAndWaitAsync("You can't use OpenChat now, because you haven't set your api key yet", 3000);
            //    return;
            //}


            // 发个消息, 将自动滚动打开, 如果已经在底部, 则将自动滚动打开
            if (messageScrollViewer.IsAtEnd())
                autoScrollToEnd = true;


            string input = ViewModel.InputBoxText.Trim();
            ViewModel.InputBoxText = string.Empty;

            ChatMessageModel requestMessageModel = new ChatMessageModel("user", input);
            ChatMessageModel responseMessageModel = new ChatMessageModel("assistant", string.Empty);

            bool responseAdded = false;

            ViewModel.Messages.Add(requestMessageModel);
            ViewModel.Messages.Add(responseMessageModel);

            _index = ViewModel.Messages.Count - 1;
            var client = new DeepSeekClient("sk-e080b2183bdd420bbf06456c9f700150");
            var request = new ChatRequest
            {
                Messages = [
                    Message.NewUserMessage(input)
                ],
                Model = DeepSeekModels.ChatModel
                //Model = DeepSeekModels.ReasonerModel
            };


            try
            {
                var choices = client.ChatStreamAsync(request, new CancellationToken());
                if (choices is null)
                {
                    Console.WriteLine(client.ErrorMsg);
                    return;
                }
                await foreach (var choice in choices)
                {
                    //await Task.Delay(00);
                    responseMessageModel.Content = choice.Delta?.Content;
                    if (!responseAdded)
                    {
                        responseAdded = true;
                        Dispatcher.Invoke(() =>
                        {
                            ViewModel.Messages.Add(responseMessageModel);
                        });
                    }
                }

                //requestMessageModel.Storage = dialogue.Ask;
                //responseMessageModel.Storage = dialogue.Answer;
            }
            catch (TaskCanceledException)
            {
                Rollback(requestMessageModel, responseMessageModel, input);
            }
            catch (Exception ex)
            {
                _ = NoteService.ShowAndWaitAsync($"{ex.GetType().Name}: {ex.Message}", 3000);

                Rollback(requestMessageModel, responseMessageModel, input);
            }

            void Rollback(
                ChatMessageModel requestMessageModel,
                ChatMessageModel responseMessageModel,
                string originInput)
            {
                ViewModel.Messages.Remove(requestMessageModel);
                ViewModel.Messages.Remove(responseMessageModel);

                if (string.IsNullOrWhiteSpace(ViewModel.InputBoxText))
                    ViewModel.InputBoxText = input;
                else
                    ViewModel.InputBoxText = $"{input} {ViewModel.InputBoxText}";
            }
        }



        [RelayCommand]
        public void Cancel()
        {
            ChatService.Cancel();
        }

        [RelayCommand]
        public void ChatOrCancel()
        {
            //if (ChatCommand.IsRunning)
            //    ChatService.Cancel();
            //else
            //    ChatCommand.Execute(null);
        }

        [RelayCommand]
        public void Copy(string text)
        {
            System.Windows.Clipboard.SetText(text);
        }



        bool autoScrollToEnd = false;

        private void CloseAutoScrollWhileMouseWheel(object sender, MouseWheelEventArgs e)
        {
            autoScrollToEnd = false;
        }

        private void EnableAutoScrollWhileAtEnd(object sender, ScrollChangedEventArgs e)
        {
            if (messageScrollViewer.IsAtEnd())
                autoScrollToEnd = true;
        }

        [RelayCommand]
        public void ScrollToEndWhileReceiving()
        {
            if (autoScrollToEnd)
                messageScrollViewer.ScrollToEnd();
        }
    }

    #region 讯飞大数据模型

    /**
     * 星火认知大模型 WebAPI 接口调用示例 接口文档（必看）：https://www.xfyun.cn/doc/spark/Web.html
     * 错误码链接：https://www.xfyun.cn/doc/spark/%E6%8E%A5%E5%8F%A3%E8%AF%B4%E6%98%8E.html （code返回错误码时必看）
     * @author iflytek
     */

    public class XunFeiApi
    {
        public delegate void MyDelegate(string message);

        public event MyDelegate OnSomethingHappened;
        ClientWebSocket webSocket0;
        CancellationToken cancellation;
        // 应用APPID（必须为webapi类型应用，并开通星火认知大模型授权）
        const string x_appid = "715f7ce5";
        // 接口密钥（webapi类型应用开通星火认知大模型后，控制台--我的应用---星火认知大模型---相应服务的apikey）
        const string api_secret = "OTFjZDJiZmYzYWFkNDIwOTQ0OWJjNGMy";
        // 接口密钥（webapi类型应用开通星火认知大模型后，控制台--我的应用---星火认知大模型---相应服务的apisecret）
        const string api_key = "ba42d9625146d4a58d6c55cf3892728c";

        string hostUrl = "https://spark-api.xf-yun.com/v1.1/chat";
        async public void Tasker(string text)
        {

            string authUrl = GetAuthUrl();
            string url = authUrl.Replace("http://", "ws://").Replace("https://", "wss://");
            using (webSocket0 = new ClientWebSocket())
            {
                try
                {
                    await webSocket0.ConnectAsync(new Uri(url), cancellation);

                    JsonRequest request = new JsonRequest();
                    request.header = new Header()
                    {
                        app_id = x_appid,
                        uid = "12345"
                    };
                    request.parameter = new Parameter()
                    {
                        chat = new Chat()
                        {
                            domain = "general",//模型领域，默认为星火通用大模型general 1.1  generalv2 2.1
                            temperature = 0.5,//温度采样阈值，用于控制生成内容的随机性和多样性，值越大多样性越高；范围（0，1）
                            max_tokens = 100,//生成内容的最大长度，范围（0，4096）
                        }
                    };
                    request.payload = new Payload()
                    {
                        message = new Message2()
                        {
                            text = new List<Content>
                                                {
                                                    new Content() { role = "user", content =text },
                                                    // new Content() { role = "assistant", content = "....." }, // AI的历史回答结果，这里省略了具体内容，可以根据需要添加更多历史对话信息和最新问题的内容。
                                                }
                        }
                    };

                    string jsonString = JsonSerializer.Serialize(request);
                    //连接成功，开始发送数据


                    var frameData2 = System.Text.Encoding.UTF8.GetBytes(jsonString.ToString());


                    await webSocket0.SendAsync(new ArraySegment<byte>(frameData2), WebSocketMessageType.Text, true, cancellation);

                    // 接收流式返回结果进行解析
                    byte[] receiveBuffer = new byte[1024];
                    WebSocketReceiveResult result = await webSocket0.ReceiveAsync(new ArraySegment<byte>(receiveBuffer), cancellation);

                    while (!result.CloseStatus.HasValue)
                    {
                        if (result.MessageType == WebSocketMessageType.Text)
                        {
                            string receivedMessage = Encoding.UTF8.GetString(receiveBuffer, 0, result.Count);
                            //将结果构造为json
                            var data = JsonSerializer.Deserialize<Response>(receivedMessage);
                            if (data.header.code == 0)
                            {
                                int sta = data.payload.choices.status;
                                for (int i = 0; i < data.payload.choices.text.Count(); i++)
                                {
                                    string rs = data.payload.choices.text[i].content;
                                    OnSomethingHappened?.Invoke(rs);

                                }
                                if (data.payload.choices.status == 2)
                                {
                                    break;
                                }
                            }
                            else
                            {
                                Console.WriteLine($"请求报错： {receivedMessage}");
                            }


                            //JObject jsonObj = JObject.Parse(receivedMessage);
                            //int code = (int)jsonObj["header"]["code"];


                            //if(0==code){
                            //    int status = (int)jsonObj["payload"]["choices"]["status"];


                            //    JArray textArray = (JArray)jsonObj["payload"]["choices"]["text"];
                            //    string content = (string)textArray[0]["content"];
                            //    resp += content;

                            //    if(status != 2){
                            //        Console.WriteLine($"已接收到数据： {receivedMessage}");
                            //    }
                            //    else{
                            //        Console.WriteLine($"最后一帧： {receivedMessage}");
                            //        int totalTokens = (int)jsonObj["payload"]["usage"]["text"]["total_tokens"];
                            //        Console.WriteLine($"整体返回结果： {resp}");
                            //        Console.WriteLine($"本次消耗token数： {totalTokens}");
                            //        break;
                            //    }

                            //}else{
                            //    Console.WriteLine($"请求报错： {receivedMessage}");
                            //}


                        }
                        else if (result.MessageType == WebSocketMessageType.Close)
                        {
                            Console.WriteLine("已关闭WebSocket连接");
                            break;
                        }

                        result = await webSocket0.ReceiveAsync(new ArraySegment<byte>(receiveBuffer), cancellation);
                    }
                }
                catch (Exception e)
                {
                    Console.WriteLine(e.Message);
                }
            }
        }
        // 返回code为错误码时，请查询https://www.xfyun.cn/document/error-code解决方案
        string GetAuthUrl()
        {
            string date = DateTime.UtcNow.ToString("r");

            Uri uri = new Uri(hostUrl);
            StringBuilder builder = new StringBuilder("host: ").Append(uri.Host).Append("\n").//
                                    Append("date: ").Append(date).Append("\n").//
                                    Append("GET ").Append(uri.LocalPath).Append(" HTTP/1.1");

            string sha = HMACsha256(api_secret, builder.ToString());
            string authorization = string.Format("api_key=\"{0}\", algorithm=\"{1}\", headers=\"{2}\", signature=\"{3}\"", api_key, "hmac-sha256", "host date request-line", sha);
            //System.Web.HttpUtility.UrlEncode

            string NewUrl = "https://" + uri.Host + uri.LocalPath;

            string path1 = "authorization" + "=" + Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes(authorization));
            date = date.Replace(" ", "%20").Replace(":", "%3A").Replace(",", "%2C");
            string path2 = "date" + "=" + date;
            string path3 = "host" + "=" + uri.Host;

            NewUrl = NewUrl + "?" + path1 + "&" + path2 + "&" + path3;
            return NewUrl;
        }




        public static string HMACsha256(string apiSecretIsKey, string buider)
        {
            byte[] bytes = System.Text.Encoding.UTF8.GetBytes(apiSecretIsKey);
            System.Security.Cryptography.HMACSHA256 hMACSHA256 = new System.Security.Cryptography.HMACSHA256(bytes);
            byte[] date = System.Text.Encoding.UTF8.GetBytes(buider);
            date = hMACSHA256.ComputeHash(date);
            hMACSHA256.Clear();

            return Convert.ToBase64String(date);

        }




    }


}



//构造请求体
public class JsonRequest
{
    public Header header { get; set; }
    public Parameter parameter { get; set; }
    public Payload payload { get; set; }
}

public class Header
{
    public string app_id { get; set; }
    public string uid { get; set; }
}

public class Parameter
{
    public Chat chat { get; set; }
}

public class Chat
{
    public string domain { get; set; }
    public double temperature { get; set; }
    public int max_tokens { get; set; }
}

public class Payload
{
    public Message2 message { get; set; }
}

public class Message2
{
    public List<Content> text { get; set; }
}

public class Content
{
    public string role { get; set; }
    public string content { get; set; }
}


#region 接受的json
public class Response
{
    public Header2 header { get; set; }
    public Payload3 payload { get; set; }
}

public class Header2
{
    public int code { get; set; }
    public string message { get; set; }
    public string sid { get; set; }
    public int status { get; set; }
}

public class Payload3
{
    public Choices choices { get; set; }
    public Usage usage { get; set; }
}

public class Choices
{
    public int status { get; set; }
    public int seq { get; set; }
    public List<Text> text { get; set; }
}

public class Text
{
    public string content { get; set; }
    public string role { get; set; }
    public int index { get; set; }
}

public class Usage
{
    public Text2 text { get; set; }
}

public class Text2
{
    public int question_tokens { get; set; }
    public int prompt_tokens { get; set; }
    public int completion_tokens { get; set; }
    public int total_tokens { get; set; }



    #endregion
    #endregion
}
